package ng.lib;

import java.awt.geom.Point2D;

public class Vector2D extends Point2D.Float {

	public <E extends Number> Vector2D(E x, E y) {
		this.x = x.floatValue();
		this.y = y.floatValue();
	}

	public Vector2D() {
		this.x = 0;
		this.y = 0;
	}

	public <E extends Number> Vector2D contractTo(E v) {
		double f = v.doubleValue() / this.getValue();
		this.x *= f;
		this.y *= f;
		return this;
	}

	public Vector2D add(Vector2D v) {
		this.x += v.x;
		this.y += v.y;
		return this;
	}

	public <E extends Number> Vector2D multiply(E f) {
		this.x *= f.floatValue();
		this.y *= f.floatValue();
		return this;
	}

	public Vector2D minus(Vector2D v) {
		this.x -= v.x;
		this.y -= v.y;
		return this;
	}

	public <E extends Number> Vector2D rotate(E a) {
		float tmpX = this.x;
		this.x = (float) ((float) this.x * Math.cos(a.doubleValue()) - this.y
				* Math.sin(a.doubleValue()));
		this.y = (float) ((float) this.y * Math.cos(a.doubleValue()) + tmpX
				* Math.sin(a.doubleValue()));
		return this;
	}

	public double getValue() {
		return Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2));

	}

	public double getAngle() {
		double v = this.getValue();
		if (v == 0)
			return 0;
		else if (y > 0)
			return Math.acos(this.x / this.getValue());
		else
			return Math.PI * 2 - Math.acos(this.x / this.getValue());

	}

	public boolean isNull() {
		return (this.x == 0 && this.y == 0);
	}

	public Vector2D inverse() {
		this.x *= -1;
		this.y *= -1;
		return this;
	}

	public <E extends Number> Vector2D extend(E v) {
		double f = v.doubleValue() / this.getValue() + 1;
		this.x *= f;
		this.y *= f;
		return this;
	}

	public Vector2D clone() {
		return new Vector2D(this.x, this.y);
	}

	public static Vector2D add(Vector2D v1, Vector2D v2) {
		return new Vector2D(v1.x + v2.x, v1.y + v2.y);
	}

	public static Vector2D minus(Vector2D v1, Vector2D v2) {
		return new Vector2D(v1.x - v2.x, v1.y - v2.y);
	}

	public String toString() {
		return "{X:" + this.x + ",Y:" + this.y + "}";
	}

}
